﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebControls;
using System.Web.UI.WebControls;
using AgileShare.Framework.Core;
using AgileShare.Framework.Library.Helpers;

namespace AgileShare.Framework.Publishing.Helpers
{
	/// <summary>
	/// This class contains helper methods for working with SharePoint Publishing Pages
	/// - All methods should be static
	/// - DO NOT USE SPContext
	/// </summary>
	public class PublishingPageHelper
	{
		/// <summary>
		/// Creates the publishing page.
		/// </summary>
		/// <param name="targetWeb">The target web.</param>
		/// <param name="pageLayoutName">Name of the page layout.</param>
		/// <param name="pageFileName">Name of the page file.</param>
		/// <param name="pageTitle">The page title.</param>
		/// <returns></returns>
		public static PublishingPage CreatePublishingPage(SPWeb targetWeb, string pageLayoutName, string pageFileName, string pageTitle)
		{
			try
			{
				PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(targetWeb);

				if (!PublishingPageExists(pubWeb, pageFileName))
				{
					PageLayout[] layouts = pubWeb.GetAvailablePageLayouts();
					PageLayout layout = null;

					foreach (PageLayout p in layouts)
					{
						if (p.Name == pageLayoutName)
						{
							layout = p;
							break;
						}
					}

					if (layout != null)
					{
						PublishingPage newPage = pubWeb.GetPublishingPages().Add(pageFileName, layout);
						newPage.Title = pageTitle;
						newPage.Update();
						newPage.CheckIn("New Page Created.");
						newPage.ListItem.File.Publish("New Page Published");
						newPage.ListItem.File.Approve("New Page Approved");
						return newPage;
					}
					else
					{
						return null;
					}
				}
				else
				{
					return GetPublishingPage(pubWeb, pageFileName);
				}
			}
			catch (Exception ex)
			{
				TraceProvider.WriteTrace(ex.Message, ex.Source, 0, TraceSeverity.Medium, ex);
				throw ex;
			}
		}

		/// <summary>
		/// Publishings the page exists.
		/// </summary>
		/// <param name="pubWeb">The pub web.</param>
		/// <param name="pageFileName">Name of the page file.</param>
		/// <returns></returns>
		private static bool PublishingPageExists(PublishingWeb pubWeb, string pageFileName)
		{
			try
			{
				foreach (PublishingPage page in pubWeb.GetPublishingPages())
				{
					// Check if page exists. If it exists, update it
					if (page.Name == pageFileName)
					{
						return true;
					}
				}
				return false;
			}
			catch
			{
				return false;
			}
		}

		/// <summary>
		/// Gets the publishing page.
		/// </summary>
		/// <param name="pubWeb">The pub web.</param>
		/// <param name="pageFileName">Name of the page file.</param>
		/// <returns></returns>
		private static PublishingPage GetPublishingPage(PublishingWeb pubWeb, string pageFileName)
		{
			try
			{
				foreach (PublishingPage page in pubWeb.GetPublishingPages())
				{
					// Check if page exists. If it exists, update it
					if (page.Name == pageFileName)
					{
						return page;
					}
				}
				return null;
			}
			catch
			{
				return null;
			}
		}

		/// <summary>
		/// Updates the publishing page field.
		/// </summary>
		/// <param name="page">The page.</param>
		/// <param name="fieldName">Name of the field.</param>
		/// <param name="fieldValue">The field value.</param>
		/// <returns></returns>
		public static PublishingPage UpdatePublishingPageField(PublishingPage page, string fieldName, string fieldValue)
		{
			try
			{
				if (page.ListItem.File.CheckOutType == SPFile.SPCheckOutType.None)
				{
					page.CheckOut();
					page.ListItem[fieldName] = fieldValue;
					page.ListItem.Update();
					page.CheckIn(fieldName + " updated.");
					page.ListItem.File.Publish("");
					page.ListItem.File.Approve("");
					return page;
				}
				else
				{
					return page;
				}
			}
			catch (Exception ex)
			{
				TraceProvider.WriteTrace(ex.Message, ex.Source, 0, TraceSeverity.Medium, ex);
				throw ex;
			}
		}

		/// <summary>
		/// Adds the web part to publishing page.
		/// </summary>
		/// <param name="page">The page.</param>
		/// <param name="webPartName">Name of the web part.</param>
		/// <param name="zoneID">The zone ID.</param>
		/// <param name="zoneIndex">Index of the zone.</param>
		/// <returns></returns>
		public static string AddWebPartToPublishingPage(PublishingPage page, string webPartName, string zoneID, int zoneIndex)
		{
			using (System.Web.UI.WebControls.WebParts.WebPart webPart = WebPartHelper.CreateWebPart(webPartName, page.PublishingWeb.Web))
			{
				string typeName = webPart.GetType().Name.ToString();
				string assemblyName = webPart.GetType().Assembly.ToString();
				if (page.ListItem.File.CheckOutType == SPFile.SPCheckOutType.None)
				{
					page.CheckOut();
					SPLimitedWebPartManager manager = page.PublishingWeb.Web.GetLimitedWebPartManager(page.Url, PersonalizationScope.Shared);
					if (!WebPartHelper.WebPartExists(assemblyName, typeName, zoneID, manager))
					{
						manager.AddWebPart(webPart, zoneID, zoneIndex);
					}
					page.CheckIn("Added Web Part");
					page.ListItem.File.Publish("");
					page.ListItem.File.Approve("");

					return webPart.ID;
				}
				else
				{
					return null;
				}
			}
		}

		/// <summary>
		/// Get a SPField object from the current publishing page.
		/// </summary>
		/// <param name="fieldName">Name of the field.</param>
		/// <param name="item">The item, like SPContext.Current.Item</param>
		/// <returns></returns>
		public static object GetFieldFromPage(string fieldName, SPItem item)
		{
			object retVal = null;
			if (item != null && item.Fields.ContainsField(fieldName))
			{
				try
				{
					retVal = item[fieldName];
				}
				catch (ArgumentException)
				{
					// ignore, assume value is null or empty
				}
			}
			return retVal;
		}

		/// <summary>
		/// Get the value of an SPField object from the Current Publishing Page
		/// </summary>
		/// <param name="fieldName">Name of the field.</param>
		/// <param name="item">The item, like SPContext.Current.Item</param>
		/// <returns></returns>
		public static string GetFieldValueFromPage(string fieldName, SPItem item)
		{
			string retVal = "";
			try
			{
				if (item != null && item.Fields.ContainsField(fieldName))
				{
					object field = item[fieldName];
					if (field != null)
					{
						retVal = field.ToString();
					}
				}
			}
			catch (ArgumentException)
			{
				// ignore, assume value is null or empty
			}
			return retVal;
		}

		/// <summary>
		/// Get the object stored in an SPField object from the Current Publishing Page
		/// </summary>
		/// <param name="fieldName">Name of the field.</param>
		/// <param name="item">The item, like SPContext.Current.Item</param>
		/// <returns></returns>
		public static object GetFieldObjectFromPage(string fieldName, SPItem item)
		{
			object retVal = null;
			try
			{
				if (item != null && item.Fields.ContainsField(fieldName))
				{
					object field = item[fieldName];
					if (field != null)
					{
						retVal = field;
					}
				}

			}
			catch (ArgumentException)
			{
				// ignore, assume value is null
			}
			return retVal;
		}

		/// <summary>
		/// Returns the SPFieldType of the specified field from the Current Publishing Page.  Returns the Error field type by default if no field is found.
		/// </summary>
		/// <param name="fieldName">Name of the field.</param>
		/// <param name="item">The item, like SPContext.Current.Item</param>
		/// <returns></returns>
		public static SPFieldType GetFieldTypeFromPage(string fieldName, SPItem item)
		{
			SPFieldType retVal = SPFieldType.Error;
			if (item != null && item.Fields.ContainsField(fieldName))
			{
				var field = item.Fields[fieldName];
				if (field != null)
				{
					retVal = field.Type;
				}
			}
			return retVal;
		}
	}
}
